import React from 'react';
import { MemoryRouter, StaticRouter } from 'react-router';
import CreateApp from '../../client/createApp';
import { renderToStaticMarkup } from 'react-dom/server';
import { createMemoryHistory } from 'history';
import { routes, getRouters } from '../../client/router';
import uid from 'uid';
import { getAsyncActions, isArray, findRouteByUrl, searchRoutes } from './helper';
import dvaServerSync from './dvaServerSync';
import memory from './routerMemory';


function findSync(branch) {
    let sync = false;
    branch.forEach((b) => {
        sync = !!b.props.sync;
    });
    return sync;
}

async function renderFragment(req, res) {
    const context = {};
    const timeout = 6000;
    const routers = getRouters(true);
    let app = CreateApp({ history: createMemoryHistory() }, true);
    app.router(options => (<StaticRouter location={req.url} context={options.context}>
        <div>
            {routers}
        </div>
    </StaticRouter>));
    const branch = findRouteByUrl(routers, req.url)
    if (branch.length === 0) {
        return {};
    } else {
        //是否异步加载
        const sync = findSync(branch);
        const asyncActions = getAsyncActions(app);
        if (!sync && asyncActions && asyncActions.length > 0) {
            const id = uid(10);
            app.use(dvaServerSync(id, (action) => {
                if (asyncActions.indexOf(action.type) > -1) {
                    return true;
                }
                return false;
            }, memory));
            const appDOM = app.start()({
                context,
            });
            let html = renderToStaticMarkup(appDOM);
            const result = await new Promise((resolve, reject) => {
                const timer = setTimeout(() => {
                    reject(new Error('render timeout'));
                }, timeout)
                memory.wait(id, () => {
                    clearTimeout(timer);
                    const curState = appDOM.props.store.getState();
                    html = renderToStaticMarkup(appDOM);
                    resolve({ html, state: curState, context });
                });
            });
            return result;
        }
        else {
            const appDOM = app.start()({
                context,
            });
            const html = renderToStaticMarkup(appDOM);
            const curState = appDOM.props.store.getState();
            return { html, state: curState, context };
        }

    }

}
export default async function render(req, res, next) {
    const url = req.url;
    try {

        const fragment = await renderFragment(req, res);

        const context = fragment.context;
        if (!context) {
            return { code: 404, url };
        } else if (context.url) {
            return {
                code: 302, url, redirect: context.url,
            };
        }
        const html = await sendHtml(fragment.html, fragment.state);
        return {
            code: 200, url, html,
        };
    } catch (e) {
        console.error(e);
        return {
            code: 500, url, error: e,
        };
    }
}
function sendHtml(html, state) {
    let scriptLink = " <script src='http://cdn.hourxu.com/vendor.js' ></script>";
    scriptLink += "<script src='http://cdn.hourxu.com/index.js'></script>";

    //加载样式
    let cssLink = "<link rel=\"stylesheet\" href='http://cdn.hourxu.com/index.css' />"

    if (process.env.NODE_ENV !== 'production') {
        scriptLink = " <script src=\"/static/vendor.js\"></script>";
        scriptLink += "<script src=\"/static/index.js\"></script>";
        cssLink = '<link rel="stylesheet" href="/static/index.css" />';

    }
    return (`
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      ${cssLink}
      <link href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
      </head>
      <body>
      <div id="app">${html}</div>   
    <script>
      window.__INITIAL_STATE__ = ${JSON.stringify(state)};
    </script>
   ${scriptLink}
      <script>
      if (navigator.serviceWorker != null) {
        navigator.serviceWorker.register('/static/sw.js')
            .then(function (registration) {
                console.log('Registered events at scope: ', registration.scope);
            });
      }
      </script>
      </body>
    </html>
    `)
}